package cn.lili.modules.order.cart.render;

import cn.hutool.core.collection.CollUtil;
import cn.lili.cache.Cache;
import cn.lili.common.enums.ResultCode;
import cn.lili.common.exception.ServiceException;
import cn.lili.common.security.AuthUser;
import cn.lili.common.security.context.UserContext;
import cn.lili.common.utils.StringUtils;
import cn.lili.modules.constant.CommonConstant;
import cn.lili.modules.goods.client.GoodsSkuClient;
import cn.lili.modules.goods.entity.dos.GoodsSku;
import cn.lili.common.utils.StringUtils;
import cn.lili.modules.goods.entity.enums.GoodsTypeEnum;
import cn.lili.modules.member.client.UserAddressClient;
import cn.lili.modules.member.client.VipClient;
import cn.lili.modules.member.entity.dos.UserAddress;
import cn.lili.modules.order.cart.entity.dto.TradeDTO;
import cn.lili.modules.order.cart.entity.enums.CartSceneEnum;
import cn.lili.modules.order.cart.entity.enums.RenderStepEnums;
import cn.lili.modules.order.cart.entity.vo.CartSkuVO;
import cn.lili.modules.order.cart.entity.vo.TradeParams;
import cn.lili.modules.order.order.entity.dos.Order;
import cn.lili.modules.order.order.entity.dos.Trade;
import cn.lili.modules.order.order.entity.dos.UserFreetaxOrderYearTotal;
import cn.lili.modules.order.order.service.OrderService;
import cn.lili.modules.order.order.service.TradeService;
import cn.lili.modules.order.order.service.UserFreetaxOrderYearTotalService;
import cn.lili.modules.system.client.DictionaryClient;
import cn.lili.modules.system.entity.dos.Dictionary;
import cn.lili.modules.system.entity.dos.LiVip;
import cn.lili.util.AesUtil;
import cn.lili.util.GoodsSkuPriceUtil;
import cn.lili.modules.system.entity.dos.LiVip;
import cn.lili.util.GoodsSkuPriceUtil;
import cn.lili.util.IdMask;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.api.UserApi;
import com.pojos.Authentication;
import com.pojos.OpenAppUser;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 交易构造&&创建
 *
 * @author Chopper
 * @since 2020-04-01 9:47 下午
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class TradeBuilder {

    /**
     * 购物车渲染步骤
     */
    private final List<CartRenderStep> cartRenderSteps;
    /**
     * 交易
     */
    private final TradeService tradeService;
    /**
     * 交易
     */
    private final OrderService orderService;


    private final UserAddressClient userAddressClient;
    private final Cache<Object> cache;

    private final VipClient vipClient;
    private final GoodsSkuClient goodsSkuClient;
    private final UserApi userApi;
    private final DictionaryClient dictionaryClient;
    private final UserFreetaxOrderYearTotalService userFreetaxOrderYearTotalService;

    private final static String KEY = "AD42F6697B035B7580E4F6693BE20BAD";
    /**
     * 构造购物车
     * 购物车与结算信息不一致的地方主要是优惠券计算和运费计算，其他规则都是一致都
     *
     * @param checkedWay 购物车类型
     * @return 购物车展示信息
     */
    public TradeDTO buildCart(CartSceneEnum checkedWay,String sessionId) {
        //读取对应购物车的商品信息
        TradeDTO tradeDTO = this.readDTO(checkedWay);
        log.info("sessionId end == {}", sessionId);
        tradeDTO.setSessionId(sessionId);
        log.info("buildCart tradeDTO = {}", JSONObject.toJSONString(tradeDTO));
        //购物车需要将交易中的优惠券取消掉
        if (checkedWay.equals(CartSceneEnum.CART)) {
            tradeDTO.setStoreCoupons(null);
            tradeDTO.setPlatformCoupon(null);
            tradeDTO.setReturnActivityUser(null);
        }

        //需要对购物车渲染
        AuthUser currentUser = UserContext.getCurrentUser();
        if (currentUser == null) {
            throw new ServiceException("请登录后操作");
        }
        LiVip liVip = vipClient.getByUserId(currentUser.getId());
        tradeDTO.setIsVip(GoodsSkuPriceUtil.getIsVip(liVip));
        //按照计划进行渲染
        renderCartBySteps(tradeDTO, RenderStepStatement.cartRender);
        log.info("tradeDTO end == {}", tradeDTO);
        return tradeDTO;
    }

    /**
     * 构造结算页面
     */
    public TradeDTO buildChecked(CartSceneEnum checkedWay,String sessionId) {
        //读取对应购物车的商品信息
        TradeDTO tradeDTO = this.readDTO(checkedWay);
        tradeDTO.setSessionId(sessionId);
        log.info("sessionId end == {}", sessionId);
        //需要对购物车渲染
        AuthUser currentUser = UserContext.getCurrentUser();
        if (currentUser == null) {
            throw new ServiceException("请登录后操作");
        }
        LiVip liVip = vipClient.getByUserId(currentUser.getId());
        tradeDTO.setIsVip(GoodsSkuPriceUtil.getIsVip(liVip));
        renderCartBySteps(tradeDTO, RenderStepStatement.checkedRender);
        return tradeDTO;
    }

    /**
     * 创建一笔交易
     * 1.构造交易
     * 2.创建交易
     *
     * @param tradeDTO 交易模型
     * @return 交易信息
     */
    public Trade createTrade(TradeDTO tradeDTO) {
        log.info("createTrade == {}", JSONObject.toJSONString(tradeDTO));
        //需要对购物车渲染
        AuthUser currentUser = UserContext.getCurrentUser();
        if (currentUser == null) {
            throw new ServiceException("请登录后操作");
        }
        LiVip liVip = vipClient.getByUserId(currentUser.getId());
        tradeDTO.setIsVip(GoodsSkuPriceUtil.getIsVip(liVip));
        if (GoodsTypeEnum.VIRTUAL_GOODS.name().equals(tradeDTO.getCheckedSkuList().get(0).getGoodsSku().getGoodsType())) {
            renderCartBySteps(tradeDTO, RenderStepStatement.tradeVirtualRender);
        } else {
            renderCartBySteps(tradeDTO, RenderStepStatement.tradeRender);
        }
        //添加order订单及order_item子订单并返回
        return tradeService.createTrade(tradeDTO);
    }


    /**
     * 获取订单实际支付的总金额
     *
     * @param orderSn 订单sn
     * @return 金额
     */
    public Double getPaymentTotal(String orderSn) {
        Order order = orderService.getBySn(orderSn);
        return order.getFlowPrice();
    }

    /**
     * 获取整笔交易
     *
     * @param way 购物车类型
     * @return 购物车视图
     */
    public TradeDTO readDTO(CartSceneEnum way) {
        //log.info("获取整笔交易");
        String key = this.getOriginKey(way);
        TradeDTO tradeDTO = StringUtils.isNotEmpty(key)?(TradeDTO) cache.get(key):null;

        //log.info("获取整笔交易>>>>,",JSONObject.toJSONString(way));
        if (tradeDTO == null) {
            AuthUser currentUser = Objects.requireNonNull(UserContext.getCurrentUser());
            tradeDTO = new TradeDTO(way);
            tradeDTO.setMemberId(currentUser.getExtendId());
            tradeDTO.setMemberName(currentUser.getUsername());
        }
        if (tradeDTO.getUserAddress() == null) {
            tradeDTO.setUserAddress(this.userAddressClient.getUserDefaultAddress(tradeDTO.getMemberId()));
        }
        if (null != tradeDTO.getReturnActivityUser()) {
            tradeDTO.setReturnActivityUser(null);
        }
        if (!tradeDTO.getCheckedSkuList().isEmpty()) {
            GoodsSku goodsSku = goodsSkuClient.getGoodsSkuById(tradeDTO.getCheckedSkuList().get(0).getGoodsSku().getId());
            //是需要上传海关的商品
            log.info("#checked# #readDTO# 是需要上传海关的商品,{}", null != goodsSku ? JSONObject.toJSONString(goodsSku) : null);
            assert goodsSku != null;
            if (null != goodsSku.getIsFree() && goodsSku.getIsFree()
                    && null != goodsSku.getThirdPartyPlatformType()
                    && Integer.valueOf(4).equals(goodsSku.getThirdPartyPlatformType())) {
                OpenAppUser openAppUser = userApi.getUserinfoByOpenId(Objects.requireNonNull(UserContext.getCurrentUser()).getOpenId());
                Authentication authentication = null;
                if (null != openAppUser) {
                    authentication = userApi.authUserInfo(openAppUser.getUId());
                    if (authentication == null || StringUtils.isEmpty(authentication.getId())) {
                        log.error("未获取到，实名认证信息=={}", JSONObject.toJSONString(openAppUser));
                        throw new ServiceException(ResultCode.NAME_OUTH);
                    }
                } else {
                    throw new ServiceException(ResultCode.NAME_OUTH);
                }
                tradeDTO.setAuthName(AesUtil.decrypt(authentication.getName(), KEY));
                tradeDTO.setAuthCardNo(authentication.getCardNo() == null ? "" : IdMask.mask(AesUtil.decrypt(authentication.getCardNo(), KEY), 3, 4));
                tradeDTO.setBuyerCardNo(AesUtil.decrypt(authentication.getCardNo(), KEY));
                if (null != tradeDTO.getUserAddress()) {
                    tradeDTO.getUserAddress().setName(AesUtil.decrypt(authentication.getName(), KEY));
                }
                //查询个人免税交易单笔限额
                List<Dictionary> freeTaxOnceMaxDic = dictionaryClient.getListByCode(CommonConstant.FREE_TAX_ONCE_MAX);
                log.info("#checked# #readDTO# 查询个人免税交易单笔限额,{}", CollUtil.isNotEmpty(freeTaxOnceMaxDic) ? JSONObject.toJSONString(freeTaxOnceMaxDic) : null);
                if (CollUtil.isNotEmpty(freeTaxOnceMaxDic)&& freeTaxOnceMaxDic.get(0).getStatus() == 1) {
                    tradeDTO.setFreeTaxOnceMax(Double.valueOf(freeTaxOnceMaxDic.get(0).getValue()));
                }
                //查询个人免税交易配置年度限额
                List<Dictionary> freeTaxYearMaxDic = dictionaryClient.getListByCode(CommonConstant.FREE_TAX_YEAR_MAX);
                log.info("#checked# #readDTO# 查询个人免税交易配置年度限额,{}", CollUtil.isNotEmpty(freeTaxYearMaxDic) ? JSONObject.toJSONString(freeTaxYearMaxDic) : null);
                if (CollUtil.isNotEmpty(freeTaxYearMaxDic) && freeTaxYearMaxDic.get(0).getStatus() == 1) {
                    tradeDTO.setFreeTaxYearMax(Double.valueOf(freeTaxYearMaxDic.get(0).getValue()));
                }
                //个人年度交易总额
                UserFreetaxOrderYearTotal userFreeTotal = userFreetaxOrderYearTotalService.selectUserFreeTaxTotalByIdCardNo(tradeDTO.getBuyerCardNo(), LocalDate.now().getYear());
                log.info("#checked# #readDTO# 个人年度交易总额,{}", userFreeTotal != null ? JSONObject.toJSONString(userFreeTotal) : null);
                if (userFreeTotal != null) {
                    tradeDTO.setFreeTaxUserTotalAmount(userFreeTotal.getTotalAmountYear());
                }
            }else {
                tradeDTO.setAuthName(null);
                tradeDTO.setAuthCardNo(null);
                tradeDTO.setBuyerCardNo(null);
                if (null != tradeDTO.getUserAddress()) {
                    UserAddress userDefaultAddress = this.userAddressClient.getUserDefaultAddress(tradeDTO.getMemberId());
                    if (userDefaultAddress != null) {
                        tradeDTO.getUserAddress().setName(userDefaultAddress.getName());
                    }
                }
            }
        }

        return tradeDTO;
    }

    /**
     * 创建交易
     * 1.获取购物车类型，不同的购物车类型有不同的订单逻辑
     * 购物车类型：购物车、立即购买、虚拟商品、拼团、积分
     * 2.校验用户的收件人信息
     * 3.设置交易的基础参数
     * 4.交易信息存储到缓存中
     * 5.创建交易
     * 6.清除购物车选择数据
     *
     * @param tradeParams 创建交易参数
     * @return 交易信息
     */
    public Trade createTrade(TradeParams tradeParams) {
        //获取购物车
        log.info("获取购物车");
        CartSceneEnum cartSceneEnum = CartSceneEnum.getCartType(tradeParams.getWay());
        TradeDTO tradeDTO = this.readDTO(cartSceneEnum);
        //设置基础属性
        log.info("设置基础属性");
        tradeDTO.setClientType(tradeParams.getClient());
        tradeDTO.setStoreRemark(tradeParams.getRemark());
        tradeDTO.setParentOrderSn(tradeParams.getParentOrderSn());
        tradeDTO.setFreePayKey(tradeParams.getFreePayKey());
        tradeDTO.setSessionId(tradeParams.getSessionId());
        //订单无收货地址校验
        if (tradeDTO.getUserAddress() == null && !GoodsTypeEnum.VIRTUAL_GOODS.name().equals(tradeDTO.getCheckedSkuList().get(0).getGoodsSku().getGoodsType())) {
            throw new ServiceException(ResultCode.MEMBER_ADDRESS_NOT_EXIST);
        }
        //是免税商品时，校验是否实名认证。以及实名认证信息是否与收货信息一致
        //UserAddress userAddress = tradeDTO.getUserAddress();
        boolean isHaiGuan = false;
        //免税商品价格
        Double freeGoodsPrice = 0d;
        for (CartSkuVO cartSkuVO : tradeDTO.getCheckedSkuList()) {
            if (cartSkuVO.getGoodsSku() == null) {
                continue;
            }
            GoodsSku goodsSku = goodsSkuClient.getGoodsSkuById(cartSkuVO.getGoodsSku().getId());
            //是需要上传海关的商品
            if (null != goodsSku.getThirdPartyPlatformType() && Integer.valueOf(4).equals(goodsSku.getThirdPartyPlatformType())) {
                isHaiGuan = true;
                //累加商品金额
                freeGoodsPrice = freeGoodsPrice + goodsSku.getPrice() * cartSkuVO.getNum();
            }
        }
        //免税商品需要，实名信息与收货人信息一致
        if (isHaiGuan) {
            /*OpenAppUser openAppUser = userApi.getUserinfoByOpenId(Objects.requireNonNull(UserContext.getCurrentUser()).getOpenId());
            Authentication authentication = null;
            if (null != openAppUser) {
                authentication = userApi.authUserInfo(openAppUser.getUId());
                if (authentication == null || StringUtils.isEmpty(authentication.getId())) {
                    log.error("未获取到，实名认证信息=={}", JSONObject.toJSONString(openAppUser));
                    throw new ServiceException(ResultCode.NAME_OUTH);
                }
            } else {
                throw new ServiceException(ResultCode.NAME_OUTH);
            }

            log.info("authentication =- {}", JSONObject.toJSONString(authentication));
            if (!authentication.getName().equals(userAddress.getName())) {
                throw new ServiceException("收货人信息与实名认证信息不匹配");
            }
            if (!authentication.getMobile().equals(userAddress.getMobile())) {
                throw new ServiceException("收货人手机号信息与实名认证信息不匹配");
            }*/

            if (StringUtils.isEmpty(tradeDTO.getAuthName())) {
                throw new ServiceException(ResultCode.NAME_OUTH);
            }

            if (!tradeDTO.getAuthName().equals(tradeDTO.getUserAddress().getName())) {
                throw new ServiceException("收货人信息与实名认证信息不匹配");
            }
            //校验价格是否超出免税价格
            //a,获取单笔限额配置、年度限额配置
            //b,用身份证号获取年度交易总额,对比
            Double freeGoodsOnceMaxRule = 5000.0, freeGoodsYearMaxRule = 26000.0;
            List<Dictionary> dictionaryOnceMaxList = dictionaryClient.getListByCode(CommonConstant.FREE_TAX_ONCE_MAX);
            log.info("#createTrade# 判断免税限额,获取字典里的免税单笔限额:{}", CollUtil.isNotEmpty(dictionaryOnceMaxList) ? JSONObject.toJSONString(dictionaryOnceMaxList) : null);
            List<Dictionary> dictionaryYearMaxList = dictionaryClient.getListByCode(CommonConstant.FREE_TAX_YEAR_MAX);
            log.info("#createTrade# 判断免税限额,获取字典里的免税年度限额:{}", CollUtil.isNotEmpty(dictionaryYearMaxList) ? JSONObject.toJSONString(dictionaryYearMaxList) : null);
            if(CollUtil.isNotEmpty(dictionaryOnceMaxList)){
                freeGoodsOnceMaxRule = Double.valueOf(dictionaryOnceMaxList.get(0).getValue());
            }
            if(CollUtil.isNotEmpty(dictionaryYearMaxList)){
                freeGoodsYearMaxRule = Double.valueOf(dictionaryYearMaxList.get(0).getValue());
            }
            if (freeGoodsPrice > freeGoodsOnceMaxRule) {
                throw new ServiceException("个人单笔免税商品消费额度为" + freeGoodsOnceMaxRule + "元，您的订单金额超出,建议您分多次下单");
            }

            UserFreetaxOrderYearTotal userFree = userFreetaxOrderYearTotalService.selectUserFreeTaxTotalByIdCardNo(tradeDTO.getBuyerCardNo(), LocalDate.now().getYear());
            log.info("#createTrade# 判断免税限额,根据身份证号查询个人年度累计交易额度, tradeDTO.getAuthCardNo:{}, LocalDate.now().getYear:{},tradeDTO:{}", tradeDTO.getAuthCardNo(), LocalDate.now().getYear(), JSONObject.toJSONString(tradeDTO));
            if (freeGoodsPrice > freeGoodsYearMaxRule || (userFree != null && userFree.getTotalAmountYear() + freeGoodsPrice > freeGoodsYearMaxRule)) {
                throw new ServiceException("您的年度免税商品消费额度" + freeGoodsYearMaxRule + "元，当前订单金额已超出，建议您部分商品让家人进行购买哟");
            }
            log.info("#createTrade# 判断免税限额, 单笔限额:{},年度限额:{},本次金额:{},累计年度交易额:{}", freeGoodsOnceMaxRule, freeGoodsYearMaxRule, freeGoodsPrice, userFree);
        }

        //构建交易
        log.info("tradeDTO == {}", JSONObject.toJSONString(tradeDTO));
        Trade trade = this.createTrade(tradeDTO);
        log.info("构建交易");
        //获取订单SN用来将优惠券存入缓存
        TradeDTO newTradeDTO = this.readDTO(cartSceneEnum);
        log.info("获取订单SN用来将优惠券存入缓存");
        newTradeDTO.setSn(trade.getSn());
        this.cleanChecked(newTradeDTO);
        log.info("结束");
        return trade;
    }


    /**
     * 重新写入购物车
     *
     * @param tradeDTO 购物车构建器最终要构建的成品
     */
    public void resetTradeDTO(TradeDTO tradeDTO) {
        cache.put(this.getOriginKey(tradeDTO.getCartSceneEnum()), tradeDTO);
    }

    /**
     * 清空购物车
     *
     * @param way 购物车类型
     */
    public void clean(String way) {
        cache.remove(this.getOriginKey(CartSceneEnum.getCartType(way)));
    }

    /**
     * 清空购物车已选择的商品
     *
     * @param tradeDTO
     */
    private void cleanChecked(TradeDTO tradeDTO) {
        List<CartSkuVO> cartSkuVOS = tradeDTO.getSkuList();
        List<CartSkuVO> deleteVos = new ArrayList<>();
        for (CartSkuVO cartSkuVO : cartSkuVOS) {
            if (Boolean.TRUE.equals(cartSkuVO.getChecked())) {
                deleteVos.add(cartSkuVO);
            }
        }
        cartSkuVOS.removeAll(deleteVos);
        //清除添加过的备注
        tradeDTO.setNeedReceipt(false);
        tradeDTO.setReceiptVO(null);
        tradeDTO.setStoreRemark(null);
        cache.put(this.getOriginKey(tradeDTO.getCartSceneEnum()), tradeDTO);
    }


    /**
     * 读取当前会员购物原始数据key
     *
     * @param cartSceneEnum 获取方式
     * @return 当前会员购物原始数据key
     */
    private String getOriginKey(CartSceneEnum cartSceneEnum) {

        //缓存key，默认使用购物车
        if (cartSceneEnum != null) {
            AuthUser currentUser = UserContext.getCurrentUser();
            if(currentUser == null){
                return null;
            }
            return cartSceneEnum.getPrefix() + currentUser.getExtendId();
        }
        throw new ServiceException();
    }


    /**
     * 根据渲染步骤，渲染购物车信息
     *
     * @param tradeDTO      交易DTO
     * @param defaultRender 渲染枚举
     */
    private void renderCartBySteps(TradeDTO tradeDTO, RenderStepEnums[] defaultRender) {
        Arrays.stream(defaultRender).forEach(e -> {log.info("购物车运算器 {}", e);});
//        Map<RenderStepEnums, Object> renderStepEnumsObjectMap = new HashMap<>();
        for (RenderStepEnums step : defaultRender) {
            for (CartRenderStep render : cartRenderSteps) {
                try {
                    if (render.step().equals(step)) {
//                        if (renderStepEnumsObjectMap.get(render.step()) != null) {
//                            continue;
//                        }
//                        renderStepEnumsObjectMap.put(render.step(), render.step());
                        tradeDTO.setCartList(tradeDTO.getCartList().stream().distinct().collect(Collectors.toList()));
                        render.render(tradeDTO);
                        System.out.println("render = " + render.step().name());
                        for (CartSkuVO cartSkuVO : tradeDTO.getSkuList()) {
                            System.out.println("cartSkuVO = " + cartSkuVO.getPriceDetailDTO().getGoodsPrice());
                        }
                    }
                } catch (ServiceException e) {
                    log.error("error ,", e);
                    throw e;
                } catch (Exception e) {
                    log.error("购物车{}渲染异常：", render.getClass(), e);
                }
            }
        }
    }
}
